package com.hnxxxy.common.aspect;

import com.hnxxxy.common.tools.Help;
import com.hnxxxy.common.annotation.LogAnno;
import com.hnxxxy.sysmgr.pojo.Log;
import com.hnxxxy.sysmgr.pojo.Staff;
import com.hnxxxy.sysmgr.service.SysLogSercice;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

@Aspect
@Component
public class WebLogAspect {

    private final Logger logger = LoggerFactory.getLogger(WebLogAspect.class);

    @Autowired
    SysLogSercice sysService;

    @Autowired
    Log log;

    /*
       设置切面点 :通过配置规则来拦截哪些需
       要增强的方法
       parameters pattern:指定方法参数(声明的类型 ),()匹配参数； (..)代表任意多个参数
       public 表示方法的声明类型为public
       * 表示任意返回值
       com.hnxxxy.*.controller.*.* 表示com.hnxxxy下面任意包下面的controller下面任意包下的的任意方法
       (..) 表示任意参数
     */
    @Pointcut("execution(public * com.hnxxxy.*.controller.*.*(..))")
    public void controllerLog() {
    }

    /*
        增强方法
     */
    @Before("controllerLog()")
    public void logBeforeController(JoinPoint joinPoint) {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();

        String descriptiontype = getControllerMethodDescriptionType(joinPoint);
        String remark = "".equals(descriptiontype) ? "暂未定义描述类型" : descriptiontype;

        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = df.format(new Date());
        // 记录下请求内容
//        logger.info("-->请求时间 : " + Help.getSystemDate());
        logger.info("-->请求时间 : " + time);
        logger.info("-->请求路径 : " + request.getRequestURL().toString());
        logger.info("-->请求描述: " + getControllerMethodDescription(joinPoint));
        logger.info("-->请求描述类型: " + remark);
        logger.info("-->请求类型名称 : " + request.getMethod());
        logger.info("-->请求的ip地址: " + request.getRemoteAddr());
        logger.info("-->请求参数 : " + Arrays.toString(joinPoint.getArgs()));
        logger.info("-->请求方法 : " + joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());

        log.Log(time,
                request.getRequestURL().toString(),
                getControllerMethodDescription(joinPoint),
                remark,
                request.getMethod(),
                request.getRemoteAddr(),
                Arrays.toString(joinPoint.getArgs()),
                joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
        if (!"".equals(descriptiontype)) {
            logger.info("-->调用logService写入日志");
            Subject subject = SecurityUtils.getSubject();
            if(subject.getPrincipal() == null){
                logger.info("-->第一次登陆");
                Object[] list = joinPoint.getArgs();
                Staff staff= (Staff)list[0];
                UsernamePasswordToken token = new UsernamePasswordToken(staff.getLoginname(),staff.getPwd());
                subject.login(token);
                sysService.insertSysLog(log);
            }else {
                sysService.insertSysLog(log);
            }
        }
    }

    @AfterThrowing(pointcut = "controllerLog()", throwing = "ex")
    public void doAfterThrowing(JoinPoint joinPoint, Exception ex) {
        String methodName = joinPoint.getSignature().getName();
        List<Object> args = Arrays.asList(joinPoint.getArgs());
        logger.info("-->请求方法：" + methodName + ",参数为：" + args + ",异常为：" + ex);
//        log.setAbnormal(ex.toString());
//        sysService.insertSysLog(log);
    }


    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param joinPoint 切点
     * @return discription
     */
    private static String getControllerMethodDescription(JoinPoint joinPoint) {
        String discription = "未标注描述信息";
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        if (!StringUtils.isEmpty(method.getAnnotation(LogAnno.class))) {
            LogAnno controllerLog = method.getAnnotation(LogAnno.class);
            discription = controllerLog.description();
        }
        return discription;
    }

    private static String getControllerMethodDescriptionType(JoinPoint joinPoint) {
        String discriptiontype = "";
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        if (!StringUtils.isEmpty(method.getAnnotation(LogAnno.class))) {
            LogAnno controllerLog = method.getAnnotation(LogAnno.class);
            discriptiontype = controllerLog.descriptiontype();
        }
        return discriptiontype;
    }

}
